import numpy as np
import random
from scipy.stats import cauchy

'''把代价矩阵为代价向量，意思是对于一个类别，只关注它是否分对了，而不关注它被错分给了哪个类别。'''

solution_size = 110
population_size=100   # 种群大小
Generation=100   # 最大迭代次数
Mutation_factor = 0.5 # 突变算子
Cross_Probability = 0.5    # 交叉概率
# D = 2   # 解空间的维度
# c_min = np.zeros((16, 16))
# print(c_min)
# c_max = np.ones((16, 16))
# print(c_max)

def captain(beta=0.5, N=population_size, D=solution_size, uF=Mutation_factor, uCr=Cross_Probability, G=Generation, c_min=np.zeros(solution_size), c_max=np.ones(solution_size)):
	'''
	自适应差分进化算法的入口
	:param N: population size 种群大小
	:param D: Dimension size 解空间大小
	:param uF: mutation factors 突变算子
	:param uCr: Cross probability 交叉概率
	:param G: Generation 代数
	:param c_min: 染色体的最小值
	:param c_max: 
	:return: 
	'''
	# 种群初始化
	C = np.zeros((G, N, D))
	fitness_values = np.zeros((G, N, D))  # 存储所有代每一个个体的适应度值，其实每次只需要保存上一代全部个体的适应度即可，因为每次只需要将当前代个体跟上一代个体的适应度值作比较。
	for i in range(N):
		C[0][i] = c_min + np.random.random() * (c_max - c_min)  # 矩阵按位对应减
		fitness_values[0][i] = evaluate_fitness(C[0][i])    # 计算当前个体的适应度
	print('差分进化种群初始化完成!')
	for g in range(G):
		S_Cr = []   # 保存所有成功的交叉概率,意思是, 成功交叉的样本中的交叉概率
		S_F = []        #同上
		print('当前位于第{}代'.format(g))
		for i in range(N):  # 循环种群内所有个体
			population_without_i = np.delete(C[g], i, 0)     # 删掉了当代种群中的第i个个体(当前旧个体)
			# 首先随机调整每个个体的突变算子值和交叉概率值
			Cr_i = np.random.normal(uCr, 0.1)
			# 很尴尬,我找了几个常用的包,random,np.random,scipy.stats, 它们内部都没有柯西分布的实现
			# 全都是标准柯西分布, 比较尴尬, 我得自己实现是么...
			F_i = np.random.standard_cauchy()       # 这里后续修改为柯西分布
			# 突变操作
			# 对当代种群的当前个体进行突变操作
			indices = random.sample(range(N - 1), 2)        # 随机寻找两个切片
			ci_mutation = C[g][i] + F_i * (population_without_i[indices[0]] - population_without_i[indices[1]])
			# 变异操作后,突变中间体的基因可能会超过上下限区间,为了保证基因取值在区间之内,对超过区间外的值赋值为边界值
			# 如果超过边界, 取边界值
			# 检查处理上边界
			ci_mutation = [ci_mutation[item_1] if ci_mutation[item_1] < c_max[item_1] else c_max[item_1] for item_1 in range(D)]
			# 检查并处理下边界
			ci_mutation = [ci_mutation[item_1] if ci_mutation[item_1] > c_min[item_1] else c_min[item_1] for item_1 in range(D)]
			# 交叉操作,对变异后的个体,根据交叉概率与适应度来确定最后的个体
			ci_new = [ci_mutation[item_1] if np.random.random() < Cr_i else C[g][i][item_1] for item_1 in range(D)]
			if evaluate_fitness(C[g][i]) > evaluate_fitness(ci_new):
				C[g+1][i] = C[g][i]
			else:
				C[g+1][i] = ci_new  # 交叉成功,保留其相关算子
				S_Cr.append(Cr_i)
				S_F.append(F_i)
		# 在每轮迭代结束,参数自适应调整
		uCr = (1-beta)*uCr + beta * (sum(S_Cr)/(len(S_Cr) if len(S_Cr) != 0 else 1))
		uF = (1-beta)*uF + beta * (sum(S_F)/(len(S_F) if len(S_F) != 0 else 1))

	# 寻找最后一代中适应度最佳的个体,为了节省时间,我应该需要记录每一轮所有个体的适应度值,方便selection操作时候进行比较
	# 也方便在最后一代中寻找最佳值

	# 另外需要别忘记,如果真实分类和预测分类一样的话,指定位置需要置为0


def evaluate_fitness(x):
	pass

